// David Eberly, Geometric Tools, Redmond WA 98052
// Copyright (c) 1998-2019
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
// File Version: 3.0.0 (2016/06/19)

#pragma once

#include <Graphics/GteComputeProgram.h>
#include <Graphics/GteProgramDefines.h>
#include <Graphics/GteVisualProgram.h>
#include <stack>

namespace gte
{

class GTE_IMPEXP ProgramFactory
{
public:
    // Abstract base class.
    virtual ~ProgramFactory();
    ProgramFactory();

    // All members are in public scope, because there are no side effects
    // when the values are modified.  The current values are used in the
    // the Create(...) functions.
    std::string version;
    std::string vsEntry, psEntry, gsEntry, csEntry;
    ProgramDefines defines;
    unsigned int flags;

    // The returned value is used as a lookup index into arrays of strings
    // corresponding to shader programs.  Currently, GLSLProgramFactory
    // returns PF_GLSL and HLSLProgramFactory returns PF_HLSL.
    enum
    {
        PF_GLSL,
        PF_HLSL,
        PF_NUM_API
    };

    virtual int GetAPI() const = 0;

    // Create a program for GPU display.  The files are loaded, converted to
    // strings, and passed to CreateFromNamedSources.  The filenames are
    // passed as the 'xsName' parameters in case the shader compiler needs
    // this for #include path searches.
    std::shared_ptr<VisualProgram> CreateFromFiles(std::string const& vsFile,
        std::string const& psFile, std::string const& gsFile);

    std::shared_ptr<VisualProgram> CreateFromSources(
        std::string const& vsSource, std::string const& psSource,
        std::string const& gsSource);

    // Create a program for GPU computing.  The file is loaded, converted to
    // a string, and passed to CreateFromNamedSource.  The filename is passed
    // the 'csName' parameters in case the shader compiler needs this for
    // #include path searches.
    std::shared_ptr<ComputeProgram> CreateFromFile(
        std::string const& csFile);

    std::shared_ptr<ComputeProgram> CreateFromSource(
        std::string const& csSource);

    // In public scope in case an effect needs a source-code string from
    // a file; for example, OverlayEffect can use this.
    static std::string GetStringFromFile(std::string const& filename);

    // Support for passing ProgramFactory objects to a function that
    // potentially modifies 'defines' or 'flags' but then needs to resstore
    // the previous state on return.  The PushDefines() function saves the
    // current 'defines' on a stack and then clears 'defines'.  The
    // PushFlags() function saves the current 'flags' on a stack and then
    // sets 'flags' to zero.  If you need to modify subelements of either
    // member, you will have to manage that on your own.
    void PushDefines();
    void PopDefines();
    void PushFlags();
    void PopFlags();

protected:
    virtual std::shared_ptr<VisualProgram> CreateFromNamedSources(
        std::string const& vsName, std::string const& vsSource,
        std::string const& psName, std::string const& psSource,
        std::string const& gsName, std::string const& gsSource) = 0;

    virtual std::shared_ptr<ComputeProgram> CreateFromNamedSource(
        std::string const& csName, std::string const& csSource) = 0;

private:
    std::stack<ProgramDefines> mDefinesStack;
    std::stack<unsigned int> mFlagsStack;

    // Prevent assignment.
    ProgramFactory& operator=(ProgramFactory const&) { return *this; }
};

}
